/*************************************************************************
	> File Name: main.h
	> Author: QiyangXia
	> Mail: 834061456@qq.com 
	> Created Time: 2021年12月31日 星期五 17时30分13秒
 ***********************************************************************/
#include "main.h"

//建表：给引擎对象分配空间
struct linklist *create_linklist()
{
	struct linklist *pp = NULL;

	pp=(struct linklist *)malloc(sizeof(struct linklist));
	if(NULL==pp)
	{
		printf("Malloc Failed\n");
		return NULL;
	}
	bzero(pp,sizeof(struct linklist));

	return pp;
}

//清空表：将所有节点空间释放，置头节点的len成员为0，pfirst成员为NULL
int clear_linklist(struct linklist *plink)
{
	struct node *pnode =NULL;
	struct node *pnext =NULL;

	pnode=plink->pfirst;
	while(pnode!=NULL)
	{
		pnext=pnode->pnext;
		destroy_node(pnode);
		pnode=pnext;
	}
	plink->pfirst=NULL;
	plink->len=0;

	return 0;
}

//删表：先清空表，然后再释放头节点的空间
int destroy_linklist(struct linklist *plink)
{
	if(plink!=NULL)
	{
		clear_linklist(plink);
		free(plink);
		plink=NULL;
	}
	return 0;
}

//创建一个节点
struct node *create_node(T *pdata)
{
	struct node *pnew=NULL;
	pnew=(struct node *)malloc(sizeof(struct node));
	if(NULL==pnew)
	{
		printf("Malloc Failed\n");
		return NULL;
	}
	bzero(pnew,sizeof(struct node));
	memcpy(&pnew->data,pdata,sizeof(T));

	return pnew;
}

//销毁一个节点：释放节点占用的内存空间
int destroy_node(struct node *pnode)
{
	if(pnode != NULL)
	{
		free(pnode);
		pnode = NULL;
	}

	return 0;
}

//求表长
int get_linklist_len(struct linklist *plink)
{
	return plink->len;
}

//判空
int is_empty_linklist(struct linklist *plink)
{
	return plink->len <= 0 ? 1 : 0;
}
/*获取带头节点的单向非循环链表的最后一个节点的地址*/
static struct node *get_last_node(struct linklist *plink)
{
	struct node *plast = NULL;

	plast = plink->pfirst;
	while(plast != NULL)
	{
		if(plast->pnext == NULL)
		{
			break;
		}
		plast = plast->pnext;
	}

	return plast;
}
//尾插：新元素插入链表，作为链表中的最后一个节点
int insert_at_tail(struct linklist *plink,struct node *pnew)
{
	struct node *plast = NULL;

	if(NULL == plink || NULL == pnew)
	{
		printf("Input param is invalid,in %s at %d\n",__FILE__,__LINE__);
		return -1;
	}

	/*得到最后一个节点地址赋值给plast指针变量*/
	plast = get_last_node(plink);

	if(plast != NULL)
	{//原表为非空表
		plast->pnext = pnew;
	}
	else
	{//原表为空表
		plink->pfirst = pnew;
	}
	pnew->pnext = NULL;

	plink->len++;

	return 0;
}
struct node * remove_at_head(struct linklist *plink)
{
	struct node *ptemp = NULL;

	if(NULL == plink)
	{
		printf("Input param is invalid,in %s at %d\n",__FILE__,__LINE__);
		return NULL;
	}
	if(is_empty_linklist(plink))
	{
		printf("The linklist is empty already,remove_at_head failed,in %s at %d\n",__FILE__,__LINE__);
		return NULL;
	}

	ptemp = plink->pfirst;
	plink->pfirst = ptemp->pnext;
	ptemp->pnext = NULL;

	plink->len--;

	return ptemp;
}
static int is_in_linklist(struct linklist *plink,struct node *pnode)
{
	struct node *pt = NULL;

	pt = plink->pfirst;
	while(pt != NULL)
	{
		if(pt == pnode)
		{
			break;
		}

		pt = pt->pnext;
	}

	return NULL == pt ? 0 : 1;
}
static struct node *get_before_node(struct linklist *plink,struct node *pnode)
{
	struct node *pbefore = NULL;
	struct node *ptemp = NULL;

	ptemp = plink->pfirst;
	while(ptemp != NULL)
	{
		if(ptemp == pnode)
		{
			break;
		}
		pbefore = ptemp;
		ptemp = ptemp->pnext;
	}

	if(ptemp == NULL)
	{
		return NULL;
	}
	else
	{
		return pbefore;
	}
}
//移除指定节点
int remove_a_node(struct linklist *plink,struct node *pnode)
{	
	struct node *pbefore = NULL;

	if(NULL == plink || NULL == pnode)
	{
		printf("Input param is invalid,in %s at %d\n",__FILE__,__LINE__);
		return -1;
	}
	if(is_empty_linklist(plink))
	{
		printf("The linklist is empty already,remove_a_node failed,in %s at %d\n",__FILE__,__LINE__);
		return -1;
	}

	/*获取指定节点前一个节点的地址*/
	pbefore = get_before_node(plink,pnode);
	if(NULL == pbefore)
	{
		if(pnode == plink->pfirst)
		{//指定节点为链表中的第一个节点
			remove_at_head(plink);
			return 0;
		}
		else
		{//指定节点不是链表中的节点，不能完成移除
			printf("The node is not in linklist,remove_a_node failed,in %s at %d\n",__FILE__,__LINE__);
			return -1;
		}
	}
	else
	{//原表中不止一个节点，并且指定节点不是第一节点
		pbefore->pnext = pnode->pnext;
		pnode->pnext = NULL;

		plink->len--;
	}
	return 0;
}

//修改:
int modify(struct node *pnode,T *pdata)
{	
	memcpy(&pnode->data,pdata,sizeof(T));

	return 0;
}

//查找：
struct node * search_by_name(struct linklist *plink,char *name)
{
	struct node *pt = NULL;

	pt = plink->pfirst;
	while(pt != NULL)
	{
		if(strcmp(name,pt->data.name) == 0)
		{
			break;
		}

		pt = pt->pnext;
	}

	return pt;
}
//查找：
struct node * search_by_no(struct linklist *plink,int *no)
{
	struct node *pt = NULL;

	pt = plink->pfirst;
	while(pt != NULL)
	{
		if(*no==pt->data.no)
		{
			break;
		}

		pt = pt->pnext;
	}

	return pt;
}


//排序方案2-----借助存放节点地址的动态数组 ---- 不会改变链表中节点的相互位置
//
static int allcmp(const void *pv1,const void *pv2)
{
	return ((*(struct node **)pv1)->data.math+(*(struct node **)pv1)->data.english+(*(struct node **)pv1)->data.chinese)-((*(struct node **)pv2)->data.math+(*(struct node **)pv2)->data.english+(*(struct node **)pv2)->data.chinese);
}
static int mathcmp(const void *pv1,const void *pv2)
{
	return (*(struct node **)pv1)->data.math-(*(struct node **)pv2)->data.math;
}

static int englishcmp(const void *pv1,const void *pv2)
{
	return (*(struct node **)pv1)->data.english-(*(struct node **)pv2)->data.english;
}
static int chinesecmp(const void *pv1,const void *pv2)
{
	return (*(struct node **)pv1)->data.chinese-(*(struct node **)pv2)->data.chinese;
}

static int bubble_sort(void *pv,int cnt,int size,int (*pfcmp)(const void *,const void *))
{
	int i = 0;
	int j = 0;
	void *pt =NULL;
	char *pstart = (char *)pv;

	//动态分配用于交换的临时空间
	pt = malloc(size);
	if(NULL == pt)
	{
		printf("Malloc failed in %s at %d\n",__FILE__,__LINE__);
		return -1;
	}
	bzero(pt,size);

	for(i = 0;i < cnt;i++)
	{
		for(j = 0;j < cnt - i - 1;j++)
		{
			if(pfcmp(pstart + j * size,pstart + (j+1) * size) > 0 )
			{
				memcpy(pt,pstart + j * size,size);
				memcpy(pstart + j * size,pstart + (j+1) *size,size);
				memcpy(pstart + (j+1) *size,pt,size);
			}
		}
	}

	//释放用于交换的临时空间
	free(pt);
	pt = NULL;

	return 0;
}

static int select_sort(void *pv,int cnt,int size,int (*pfcmp)(const void *,const void *))
{
	int i = 0;
	int j = 0;
	int min = 0;
	void *pt =NULL;
	char *pstart = (char *)pv;

	//动态分配用于交换的临时空间
	pt = malloc(size);
	if(NULL == pt)
	{
		printf("Malloc failed in %s at %d\n",__FILE__,__LINE__);
		return -1;
	}
	bzero(pt,size);

	for(i = 0;i < cnt;i++)
	{
		min = i;

		for(j = i + 1;j < cnt;j++)
		{
			if(pfcmp(pstart + j * size,pstart + min *size) < 0)
			{
				min = j;
			}
		}

		if(min != i)
		{
			memcpy(pt,pstart + min * size,size);
			memcpy(pstart + min * size,pstart + i * size,size);
			memcpy(pstart + i * size,pt,size);
		}
	}
	
	//释放用于交换的临时空间
	free(pt);
	pt = NULL;
	return 0;
}

static int insert_sort(void *pv,int cnt,int size,int (*pfcmp)(const void *,const void *))
{
	int i = 0;
	int j = 0;
	void *pt =NULL;
	char *pstart = (char *)pv;

	//动态分配用于交换的临时空间
	pt = malloc(size);
	if(NULL == pt)
	{
		printf("Malloc failed in %s at %d\n",__FILE__,__LINE__);
		return -1;
	}
	bzero(pt,size);

	for(i = 1;i < cnt;i++)
	{
		memcpy(pt,pstart + i * size,size);
		for(j = i -1;j >= 0;j--)
		{
			if(pfcmp(pstart + j * size,pt) > 0)
			{
				memcpy(pstart + (j+1) * size,pstart + j * size,size);
			}
			else
			{
				break;
			}
		}
		memcpy(pstart + (j+1) * size,pt,size);
	}

	
	//释放用于交换的临时空间
	free(pt);
	pt = NULL;
	return 0;
}

struct node **sort_person_linklist_by_all(struct linklist *plink)
{
	struct node **ppsorted = NULL;
	struct node *ptemp = NULL;
	int i = 0;

	ppsorted = (struct node **)malloc(plink->len * sizeof(struct node *));
	if(NULL == ppsorted)
	{
		printf("Malloc Failed,%s:%d\n",__FILE__,__LINE__);
		return NULL;
	}
	memset(ppsorted,0,plink->len * sizeof(struct node *));

	ptemp = plink->pfirst;
	while(ptemp != NULL)
	{
		*(ppsorted + i) = ptemp;
		i++;
		ptemp = ptemp->pnext;
	}

	qsort(ppsorted,plink->len,sizeof(struct node *),allcmp);

	return ppsorted;
}
struct node **sort_person_linklist_by_math(struct linklist *plink)
{
	struct node **ppsorted = NULL;
	struct node *ptemp = NULL;
	int i = 0;

	ppsorted = (struct node **)malloc(plink->len * sizeof(struct node *));
	if(NULL == ppsorted)
	{
		printf("Malloc Failed,%s:%d\n",__FILE__,__LINE__);
		return NULL;
	}
	memset(ppsorted,0,plink->len * sizeof(struct node *));

	ptemp = plink->pfirst;
	while(ptemp != NULL)
	{
		*(ppsorted + i) = ptemp;
		i++;
		ptemp = ptemp->pnext;
	}

	insert_sort(ppsorted,plink->len,sizeof(struct node *),mathcmp);

	return ppsorted;
}
struct node **sort_person_linklist_by_english(struct linklist *plink)
{
	struct node **ppsorted = NULL;
	struct node *ptemp = NULL;
	int i = 0;

	ppsorted = (struct node **)malloc(plink->len * sizeof(struct node *));
	if(NULL == ppsorted)
	{
		printf("Malloc Failed,%s:%d\n",__FILE__,__LINE__);
		return NULL;
	}
	memset(ppsorted,0,plink->len * sizeof(struct node *));

	ptemp = plink->pfirst;
	while(ptemp != NULL)
	{
		*(ppsorted + i) = ptemp;
		i++;
		ptemp = ptemp->pnext;
	}

	select_sort(ppsorted,plink->len,sizeof(struct node *),englishcmp);

	return ppsorted;
}
struct node **sort_person_linklist_by_chinese(struct linklist *plink)
{
	struct node **ppsorted = NULL;
	struct node *ptemp = NULL;
	int i = 0;

	ppsorted = (struct node **)malloc(plink->len * sizeof(struct node *));
	if(NULL == ppsorted)
	{
		printf("Malloc Failed,%s:%d\n",__FILE__,__LINE__);
		return NULL;
	}
	memset(ppsorted,0,plink->len * sizeof(struct node *));

	ptemp = plink->pfirst;
	while(ptemp != NULL)
	{
		*(ppsorted + i) = ptemp;
		i++;
		ptemp = ptemp->pnext;
	}

	bubble_sort(ppsorted,plink->len,sizeof(struct node *),chinesecmp);

	return ppsorted;
}
int print_sort_result(struct node **ppsorted,int cnt)
{
	int i = 0;

	printf("%-4s%-20s%-4s%-10s%-10s%-10s\n","NO","Name","Sex","MATH","ENGLISH","CHINESE");

	for(i = 0;i < cnt;i++)
	{
		printf("%-4d%-20s%-4c%-10.2f%-10.2f%-10.2f\n",
		       (*(ppsorted+i))->data.no,
		       (*(ppsorted+i))->data.name,
		       (*(ppsorted+i))->data.sex,
		       (*(ppsorted+i))->data.math,
		       (*(ppsorted+i))->data.english,
		       (*(ppsorted+i))->data.chinese
		      );
	}

	return 0;
}

int free_sort_result(struct node **ppsorted)
{
	if(ppsorted != NULL)
	{
		free(ppsorted);
		ppsorted = NULL;
	}

	return 0;
}


//打印所有联系人
int print_all_person(struct linklist *plink)
{
	struct node *pnode = NULL;

	printf("%-4s%-20s%-4s%-10s%-10s%-10s\n","NO","Name","Sex","MATH","ENGLISH","CHINESE");
	pnode = plink->pfirst;
	while(pnode != NULL)
	{
		printf("%-4d%-20s%-4c%-10.2f%-10.2f%-10.2f\n",
		       pnode->data.no,
		       pnode->data.name,
		       pnode->data.sex,
		       pnode->data.math,
		       pnode->data.english,
		       pnode->data.chinese
		      );
		pnode = pnode->pnext;
	}
	return 0;
}
int write_in(struct linklist *plink)
{
	FILE *pf;
	char pDate[20];
	time_t t;
	t=time(NULL);
	struct tm *n=NULL;
	n=localtime(&t);
	sprintf(pDate,"%02d_%02d_%02d_Grade.txt",(n->tm_year)%100,1+n->tm_mon,n->tm_mday);

	struct node *ptemp=NULL;
	ptemp = plink->pfirst;
	if((pf=fopen(pDate,"wt"))==NULL)
	{
		printf("打开文件失败\n");
		return -1;
	}
	while(ptemp!=NULL)
	{
		//fwrite(ptemp,sizeof(struct node *),1,pf);
		fprintf(pf,"%d ",ptemp->data.no);
		fprintf(pf,"%s ",ptemp->data.name);
		fprintf(pf,"%c ",ptemp->data.sex);
		fprintf(pf,"%.2f ",ptemp->data.math);
		fprintf(pf,"%.2f ",ptemp->data.english);
		fprintf(pf,"%.2f ",ptemp->data.chinese);
		fprintf(pf,"%c",'\n');
		ptemp=ptemp->pnext;
	}
	printf("学生成绩已导出\n");
	fclose(pf);
	pf=NULL;
	
	return 0;
}

static char *myreadline(FILE *pf);
int read_in(struct linklist *plink)
{
	FILE *pf;
	char pDate[20];
	time_t t;
	t=time(NULL);
	struct tm *n=NULL;
	n=localtime(&t);
	int linecnt = 0;
	char *pret = NULL;
	char sexbuf[4] = "";
	sprintf(pDate,"%02d_%02d_%02d_Grade.txt",(n->tm_year)%100,1+n->tm_mon,n->tm_mday);
	
	struct node *ptemp=NULL;

	ptemp = plink->pfirst;
	if((pf=fopen(pDate,"r"))==NULL)
	{
		printf("打开文件失败\n");
		return -1;
	}

	/*读行数*/
	pret = myreadline(pf);
	while(pret != NULL)
	{
		linecnt++;
		free(pret);
		pret = myreadline(pf);
	}
	fseek(pf,0,SEEK_SET);
	/*分配空间*/
	ptemp = (struct node *)malloc(sizeof(struct node));
	if(NULL == ptemp)
	{
		fclose(pf);
		pf = NULL;
		printf("Malloc Failed!\n");
		return 2;
	}
	clear_linklist(plink);
	fseek(pf,0,SEEK_SET);
	do
	{
		fscanf(pf,"%d%s%s%f%f%f",
			  &ptemp->data.no,
			  ptemp->data.name,
			  sexbuf,
			  &ptemp->data.math,
			  &ptemp->data.english,
			  &ptemp->data.chinese
			  );
		ptemp->data.sex = sexbuf[0];
		//printf("\n\n\n%d %s %c %f %f %f \n",ptemp->data.no,ptemp->data.name,ptemp->data.sex,ptemp->data.math,ptemp->data.english,ptemp->data.chinese);
		insert_at_tail(plink,ptemp);
		ptemp=create_node(&ptemp->data);
		linecnt--;
	//	printf("%d\n",linecnt);
		//ptemp = ptemp->pnext;
	}while(linecnt>1);

	printf("学生成绩已录入\n");

	/*关闭文件*/
	fclose(pf);
	pf = NULL;
}
/*Don't forget free return memory*/
static char *myreadline(FILE *pf)
{
	int linecnt = 0;
	int oldloc = 0;
	int ret = 0;
	char *pout = NULL;
	char *pret = NULL;
	/*1. 获取指示器指示的字符位置所在行的总字符数----linecnt*/
		/*保存位置指示器的当前指示位置- ftell*/
	oldloc = ftell(pf);

		/*循环读取单个字符直到文件尾或行尾，每读一个字符linecnt++*/
	ret = fgetc(pf);
	while(ret >= 0 && ret != '\n')
	{
		linecnt++;
		ret = fgetc(pf);
	}
	if(ret == '\n')
	{
		linecnt++;//'\n'
	}
		/*恢复位置指示器指示的原位置--fseek*/
	fseek(pf,oldloc,SEEK_SET);
	/*2. 分配linecnt+1字节的内存空间*/
	if(linecnt <= 0)	
	{
		return NULL;
	}
	linecnt++;//'\0'
	pout = (char *)malloc(linecnt);
	if(NULL == pout)
	{
		printf("Malloc failed ! %s:%d\n",__FILE__,__LINE__);
		return NULL;
	}
	memset(pout,0,linecnt);
	/*3. 读出整行*/
	pret = fgets(pout,linecnt,pf);
	if(NULL == pret)
	{
		free(pout);
		pout = NULL;
		printf("read a line failed! %s:%d\n",__FILE__,__LINE__);
		return NULL;
	}
	/*4. 返回动态空间的首地址*/
	return pout;
}

int print_a_person(struct node *pnode)
{
	printf("%-4s%-20s%-4s%-10s%-10s%-10s\n","NO","Name","Sex","MATH","ENGLISH","CHINESE");
	printf("%-4d%-20s%-4c%-10.2f%-10.2f%-10.2f\n",
		pnode->data.no,
		pnode->data.name,
		pnode->data.sex,
		pnode->data.math,
		pnode->data.english,
		pnode->data.chinese
	      );
	return 0;
}
